﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using QuanserClient;
using ZedGraph;

namespace Controlador_TB1
{
    public partial class FormPrincipal : Form
    {
        private enum SinaisCalculados
        {
            PORTA_0,
            PORTA_1,
            PORTA_2,
            PORTA_3,
            PORTA_4,
            PORTA_5,
            PORTA_6,
            PORTA_7,
            Erro,
            EntradaDegrau,
            EntradaSenoidal,
            EntradaQuadrada,
            EntradaDenteSerra
        }
        double tempo_s = 0;
        double valor_final = 0;


        private const int QTD_PORTAS = 8;
        private const int PORTA_QUANSER = 20081;

        private static int idGenerator;
        private readonly Sinal SINAL_NENHUM = new Sinal(idGenerator++, "Nenhum", 0);
        private System.Threading.Timer temporizador;
        private IQuanserClient quanserClient;
        private QuanserServer quanserServer;
        private TimeSpan runningTime;
        private DateTime lastRun;

        private List<Sinal> sinais = new List<Sinal>();

        private delegate Object LerValorComboBoxCallback(ComboBox cbx);
        private delegate String LerValorTextBoxCallback(TextBox txt);


        bool Mostra_Grafico = true;
        private int contadorUnidadeTempo;

        public FormPrincipal()
        {
            InitializeComponent();

            Inicializar();
        }

        private void Inicializar()
        {
            //Portas portas = new Portas(QTD_PORTAS, true, Orientation.Horizontal);

            //portas.Location = new Point(6, 19);

            //gbxPortas.Controls.Add(portas);

            quanserServer = new QuanserServer(PORTA_QUANSER);
            quanserClient = new QuanserClient.QuanserClient(quanserServer);

            MontarPortas();
            AtualizarOpcoesGrafico();
            //MontarSinais();
        }

        private void AdicionarSinal(String descricao)
        {
            Sinal novoSinal = new Sinal();

            novoSinal.Id = idGenerator++;
            novoSinal.Descricao = descricao;

            AtualizarOpcoesGrafico();
        }

        private void AtualizarOpcoesGrafico()
        {
            AtualizarOpcaoGrafico(cbxLinhaAzul);
            AtualizarOpcaoGrafico(cbxLinhaVerde);
            AtualizarOpcaoGrafico(cbxLinhaAmarela);
            AtualizarOpcaoGrafico(cbxLinhaVermelha);
            AtualizarOpcaoGrafico(cbxLinhaBranca);
            AtualizarOpcaoGrafico(cbxLinhaLaranja);
        }

        private void AtualizarOpcaoGrafico(ComboBox cbx)
        {
            object antigoItemSelecionado = cbx.SelectedItem;
            object antigoValorSelecionado = cbx.SelectedValue;

            cbx.Items.Add(SINAL_NENHUM);

            foreach (Sinal sinal in sinais) 
            {
                cbx.Items.Add(sinal);
            }
            
            cbx.ValueMember = "Id";
            cbx.DisplayMember = "Descricao";

            if (antigoItemSelecionado != null && cbx.Items.Contains(antigoItemSelecionado))
            {
                cbx.SelectedValue = antigoValorSelecionado;
            }
            else
            {
                cbx.SelectedIndex = 0;
            }
        }

        private void Grafico()
        {
            GraphPane myPane = zgc.GraphPane;

            PointPairList list = new PointPairList();
            //PointPairList list2 = new PointPairList();
            double x = 0;
            double y = 0;

            zgc.GraphPane.YAxis.Scale.Min = -5;
            zgc.GraphPane.YAxis.Scale.Max = 19;

            LineItem curve = myPane.AddCurve("Step", list, Color.Red, SymbolType.Circle);
            //LineItem curve2 = myPane.AddCurve("Step", list2, Color.Blue, SymbolType.Triangle);



            double T = 1;
            double s = 0;
            double xx = 0.1;

            double valor_final = 0;

            while (Mostra_Grafico)
            {
                valor_final = 4.5 + 4.5 * Math.Sin(((2 * Math.PI) * s) / T);

                s = s + 0.1;

                if (s > 1)
                    s = 0;

                if (xx * 10 < contadorUnidadeTempo)
                {
                    list.Add(xx, sinais[0].PontoList[(int)(xx * 10)].ValorAmplitude);
                //list2.Add(xx, valor_final*2);
                //quanserClient.write(0, (valor_final));

                

                    zgc.GraphPane.XAxis.Scale.Min = (xx - 10);
                    zgc.GraphPane.XAxis.Scale.Max = (xx + 10);
                    zgc.Invalidate();

                    xx = xx + 0.1;
                }

                Thread.Sleep(100);
            }

        }

        private void MontarPortas()
        {
            for (int i = 0; i < QTD_PORTAS; i++)
            {
                cbxPortaEntradaMF.Items.Add(i);
                cbxPortaSaidaMA.Items.Add(i);
                cbxPortaSaidaMF.Items.Add(i);
            }

            cbxPortaEntradaMF.SelectedIndex = 0;
            cbxPortaSaidaMA.SelectedIndex = 0;
            cbxPortaSaidaMF.SelectedIndex = 1;
        }

        private void btnIniciar_Click(object sender, EventArgs e)
        {
            try
            {
                Conectar();

                if (true)
                {
                    Sinal sinalMF = new Sinal();

                    sinalMF.Id = idGenerator++;
                    sinalMF.Descricao = "Nível Tanque";
                    sinalMF.Periodo = int.Parse(txtPeriodoControlador.Text);

                    sinais.Add(sinalMF);

                    temporizador = new System.Threading.Timer(ControladorMalhaFechada, null, 0, int.Parse(txtPeriodoControlador.Text));

                    AtualizarOpcoesGrafico();
                }

                if (false)
                {
                    if (rbtEntradaDegrauMA.Checked)
                    {
                        temporizador = new System.Threading.Timer(FuncaoDegrau, null, 0, int.Parse(txtPeriodoEntrada.Text));
                    }
                    else if (rbtEntradaOndaSenoidalMA.Checked)
                    {
                        temporizador = new System.Threading.Timer(FuncaoSenoidal, null, 0, int.Parse(txtPeriodoEntrada.Text));
                    }
                }
            }
            catch (QuanserClientException qcex)
            {
                MessageBox.Show(this, qcex.Message, "ERRO", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void Conectar()
        {
            quanserClient.Connect();
        }

        private void ControladorMalhaFechada(Object stateInfo)
        {
            try
            {
                int portaEntrada = 1;
                int portaSaida = 0;

                double valorReferencia = double.Parse(LerValorTextBox(txtValorReferenciaMF));
                double valorEntrada = quanserClient.Read(portaEntrada);
                double valorErro = valorReferencia - valorEntrada;

                sinais[0].PontoList.Add(new PontoSinal(contadorUnidadeTempo, valorEntrada));

                contadorUnidadeTempo++;

                if (valorErro > 3 || valorErro < 0)
                {
                        int i = 1;
                }

                quanserClient.Write(portaSaida, valorErro);
            }
            catch (Exception ex)
            {

            }
        }

        private void FuncaoDegrau(Object stateInfo)
        {
            try
            {
                int portaSaida = (int)LerValorComboBox(cbxPortaSaidaMA);
                double amplitude = double.Parse(LerValorTextBox(txtAmplitudeEntrada));

                quanserClient.Write(portaSaida, amplitude);
            }
            catch (Exception ex)
            {
                //MessageBox.Show(qcex.Message);
            }
        }

        private void FuncaoSenoidal(Object stateInfo)
        {
            //int portaSaida = 0;// (int)LerValorComboBox(cbxPortaSaidaMA);

            if (tempo_s > 1)
                tempo_s = 0;
            else
                tempo_s = tempo_s + 0.1;

            valor_final = 0.5 + 0.5 * Math.Sin(((2 * Math.PI) * tempo_s) / 10);

            
            //xx = xx + 0.1;

            

            //list.Add(xx, valor_final);
            //list2.Add(xx, valor_final * 2);
            //quanserClient.write(0, (valor_final));

            try
            {
                quanserClient.Write(0, valor_final);
            }
            catch { }
        }
        private Object LerValorComboBox(ComboBox cbx)
        {
            if (cbx.InvokeRequired)
            {
                LerValorComboBoxCallback callback = new LerValorComboBoxCallback(LerValorComboBox);

                return (Object)this.Invoke(callback, new object[] { cbx });
            }
            else
            {
                return cbx.SelectedItem;
            }
        }

        private String LerValorTextBox(TextBox txt)
        {
            if (txt.InvokeRequired)
            {
                LerValorTextBoxCallback callback = new LerValorTextBoxCallback(LerValorTextBox);

                return (String)this.Invoke(callback, new object[] { txt });
            }
            else
            {
                return txt.Text;
            }
        }

        private void btnParar_Click(object sender, EventArgs e)
        {
            temporizador.Change(Timeout.Infinite, Timeout.Infinite);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Mostra_Grafico = true;

            Thread oThread = new Thread(new ThreadStart(Grafico));
            oThread.Start();
           
        }


    }
}
